package com.niiwoo.civet.account.service.local.withholdProtocol;

import com.alibaba.fastjson.JSON;
import com.dangdang.ddframe.rdb.sharding.api.HintManager;
import com.dangdang.ddframe.rdb.sharding.hint.HintManagerHolder;
import com.github.pagehelper.PageHelper;
import com.niiwoo.civet.account.dao.entity.AccountBase;
import com.niiwoo.civet.account.dao.entity.BankCard;
import com.niiwoo.civet.account.dao.entity.BankCardRebindOrder;
import com.niiwoo.civet.account.dao.entity.PayChannel;
import com.niiwoo.civet.account.dao.entity.WithholdProtocolApplyOrder;
import com.niiwoo.civet.account.dao.entity.WithholdProtocolChannel;
import com.niiwoo.civet.account.dao.entity.WithholdProtocolConfirmOrder;
import com.niiwoo.civet.account.dao.entity.WithholdProtocolConfirmOrderExample;
import com.niiwoo.civet.account.dao.entity.WithholdProtocolSigned;
import com.niiwoo.civet.account.dao.entity.WithholdProtocolSignedExample;
import com.niiwoo.civet.account.dao.mapper.AccountBaseMapperExt;
import com.niiwoo.civet.account.dao.mapper.BankCardMapperExt;
import com.niiwoo.civet.account.dao.mapper.BankCardRebindOrderMapperExt;
import com.niiwoo.civet.account.dao.mapper.BankTypeMapperExt;
import com.niiwoo.civet.account.dao.mapper.PayChannelMapperExt;
import com.niiwoo.civet.account.dao.mapper.WithholdProtocolApplyOrderMapper;
import com.niiwoo.civet.account.dao.mapper.WithholdProtocolChannelMapperExt;
import com.niiwoo.civet.account.dao.mapper.WithholdProtocolConfirmOrderMapper;
import com.niiwoo.civet.account.dao.mapper.WithholdProtocolSignedMapper;
import com.niiwoo.civet.account.dao.mapper.WithholdProtocolSignedMapperExt;
import com.niiwoo.civet.account.dto.response.ApplyWithholdProtocolResponseDTO;
import com.niiwoo.civet.account.dto.response.ConfirmWithholdProtocolResponseDTO;
import com.niiwoo.civet.account.dto.response.WithholdProtocolResultDTO;
import com.niiwoo.civet.account.service.local.AccountService;
import com.niiwoo.civet.account.service.local.BankCardService;
import com.niiwoo.tripod.lanmao.component.LanMaoSequence;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import com.niiwoo.tripod.lanmao.request.ProtocolSignQueryRequest;
import com.niiwoo.tripod.lanmao.response.ProtocolSignQueryResponse;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Service
public class WithholdProtocolServiceImpl extends WithholdProtocolHandler implements WithholdProtocolService {

    @Autowired
    private AccountBaseMapperExt accountBaseMapperExt ;
    @Autowired
    private AccountService accountService;
    @Autowired
    private BankCardMapperExt bankCardMapperExt;
    @Autowired
    private BankTypeMapperExt bankTypeMapperExt;
    @Autowired
    private WithholdProtocolChannelMapperExt withholdProtocolChannelMapperExt;
    @Autowired
    private WithholdProtocolSignedMapperExt withholdProtocolSignedMapperExt;
    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;
    @Autowired
    private WithholdProtocolApplyOrderMapper withholdProtocolApplyOrderMapper;
    @Autowired
    private LanMaoSequence lanMaoSequence;
    @Autowired
    private PayChannelMapperExt payChannelMapperExt;
    @Autowired
    private WithholdProtocolConfirmOrderMapper withholdProtocolConfirmOrderMapper;
    @Autowired
    private WithholdProtocolSignedMapper withholdProtocolSignedMapper ;
    @Autowired
    private BankCardService bankCardService;
    @Autowired
    private BankCardRebindOrderMapperExt bankCardRebindOrderMapperExt;


    @Override
    public ApplyWithholdProtocolResponseDTO applyWithholdProtocol(String userId, String orgId) {
        super.setMasterRouteOnly();
        WithholdProtocolApplyOrder withholdProtocolApplyOrder = verifyApplyOrder(userId,orgId);
        createApplyOrder(withholdProtocolApplyOrder);
        withholdProtocolApplyOrder = submitApplyChannel(withholdProtocolApplyOrder);
        saveApplyResult(withholdProtocolApplyOrder);

        ApplyWithholdProtocolResponseDTO applyWithholdProtocolResponseDTO = new ApplyWithholdProtocolResponseDTO();
        if(withholdProtocolApplyOrder.getStatus().equals(Status.SUCCESS.getCode())){
            applyWithholdProtocolResponseDTO.setResult(Boolean.TRUE);
            applyWithholdProtocolResponseDTO.setOrderId(withholdProtocolApplyOrder.getId());
        }else{
            applyWithholdProtocolResponseDTO.setResult(Boolean.FALSE);
            applyWithholdProtocolResponseDTO.setOrderId(withholdProtocolApplyOrder.getId());
            applyWithholdProtocolResponseDTO.setErrorCode(withholdProtocolApplyOrder.getErrorCode());
            applyWithholdProtocolResponseDTO.setErrorMessage(withholdProtocolApplyOrder.getErrorMessage());
        }
        return applyWithholdProtocolResponseDTO;
    }

    /**
     * 验证申请信息：
     *     存管账号是否开能；
     *     银行卡是否支持代扣；
     *     当前银行卡是否开通指定支付公司
     *     生成当前请求订单
     * @param userId
     * @param orgId
     * @return
     */
    private WithholdProtocolApplyOrder verifyApplyOrder(String userId, String orgId){
        Assert.hasLength(userId,"userId不能为空");
        Assert.hasLength(orgId,"orgId不能为空");
        AccountBase accountBase = accountService.getAccount(userId, UserRoleEnum.BORROWERS,orgId);
        Optional.ofNullable(accountBase).orElseThrow(() -> new BizException("ACC10004"));

        BankCardRebindOrder bankCardRebindOrder = bankCardRebindOrderMapperExt.selectCurrentRebindOrderWithAccountIds(accountBase.getUserId(), Arrays.asList(accountBase.getId()));
        if( bankCardRebindOrder != null ) {
            throw new BizException("ACC40008");
        }

        BankCard bankCard = bankCardService.loadBankCard(accountBase);
        WithholdProtocolChannel withholdProtocolChannel = withholdProtocolChannelMapperExt.selectByBankTypeId(bankCard.getBankTypeId());
        Optional.ofNullable(withholdProtocolChannel).orElseThrow(() -> new BizException("ACC45002"));
        PayChannel payChannel = payChannelMapperExt.selectByPrimaryKey(withholdProtocolChannel.getPayChannelId());
        Optional.ofNullable(payChannel).orElseThrow(() -> new BizException("ACC45004"));
        List<WithholdProtocolSigned> withholdProtocolSignedList = this.checkWithholdProtocolSigned(bankCard.getRealName(),bankCard.getIdCard(),bankCard.getMobileNo(),bankCard.getBankAccountNo(),payChannel.getId());
        for(WithholdProtocolSigned vo : withholdProtocolSignedList){
            if(vo.getPayChannelId().equals(payChannel.getId())){
                throw new BizException("ACC45003");    //当前用户已签约
            }
        }

        WithholdProtocolApplyOrder withholdProtocolApplyOrder = new WithholdProtocolApplyOrder();
        withholdProtocolApplyOrder.setId(snowflakeIdWorker.nextId());
        withholdProtocolApplyOrder.setAccountId(accountBase.getId());
        withholdProtocolApplyOrder.setBankCardId(bankCard.getId());
        withholdProtocolApplyOrder.setPayChannelId(payChannel.getId());
        withholdProtocolApplyOrder.setExpectPayCompany(payChannel.getChannelCode());
        withholdProtocolApplyOrder.setCreateTime(new Date());
        withholdProtocolApplyOrder.setUpdateTime(new Date());
        withholdProtocolApplyOrder.setPlatformUserNo(accountBase.getAccountNo());
        withholdProtocolApplyOrder.setRequestNo(lanMaoSequence.getRequestNo());
        withholdProtocolApplyOrder.setStatus(Status.INIT.getCode());
        withholdProtocolApplyOrder.setUserId(accountBase.getUserId());
        return withholdProtocolApplyOrder;
    }

    /**
     * 创建订单
     * @param withholdProtocalApplyOrder
     */
    @Transactional(propagation = Propagation.REQUIRED)
    public void createApplyOrder(WithholdProtocolApplyOrder withholdProtocalApplyOrder){
        withholdProtocolApplyOrderMapper.insert(withholdProtocalApplyOrder);
    }

    /**
     * 提交存管请求
     * @param withholdProtocalApplyOrder
     */
    protected WithholdProtocolApplyOrder submitApplyChannel(WithholdProtocolApplyOrder withholdProtocalApplyOrder){
         return super.protocolSign(withholdProtocalApplyOrder);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void saveApplyResult(WithholdProtocolApplyOrder withholdProtocolApplyOrder){
        withholdProtocolApplyOrderMapper.updateByPrimaryKeySelective(withholdProtocolApplyOrder);
    }



    @Override
    public ConfirmWithholdProtocolResponseDTO confirmWithholdProtocol(Long orderId, String securityCode) {
        super.setMasterRouteOnly();
        WithholdProtocolConfirmOrder withholdProtocolConfirmOrder = verifyConfirmOrder(orderId,securityCode);
        createConfirmOrder(withholdProtocolConfirmOrder);
        withholdProtocolConfirmOrder = submitConfirmOrder(withholdProtocolConfirmOrder);
        saveConfirmOrder(withholdProtocolConfirmOrder);

        ConfirmWithholdProtocolResponseDTO confirmWithholdProtocolResponseDTO = new ConfirmWithholdProtocolResponseDTO();
        if( withholdProtocolConfirmOrder.getStatus().equals(Status.SUCCESS.getCode())){
            confirmWithholdProtocolResponseDTO.setResult(Boolean.TRUE);
        }else{
            confirmWithholdProtocolResponseDTO.setResult(Boolean.FALSE);
            confirmWithholdProtocolResponseDTO.setErrorCode(withholdProtocolConfirmOrder.getErrorCode());
            confirmWithholdProtocolResponseDTO.setErrorMessage(withholdProtocolConfirmOrder.getErrorMessage());
            confirmWithholdProtocolResponseDTO.setChannelErrorCode(withholdProtocolConfirmOrder.getChannelErrorCode());
            confirmWithholdProtocolResponseDTO.setChannelErrorMessage(withholdProtocolConfirmOrder.getChannelErrorMessage());
        }

        return confirmWithholdProtocolResponseDTO;
    }

    private WithholdProtocolConfirmOrder verifyConfirmOrder(Long orderId, String securityCode){
        Assert.notNull(orderId,"orderId不能为空");
        Assert.hasText(securityCode,"securityCode不能为空");
        WithholdProtocolApplyOrder withholdProtocolApplyOrder = withholdProtocolApplyOrderMapper.selectByPrimaryKey(orderId);
        Optional.ofNullable(withholdProtocolApplyOrder).orElseThrow(() -> new BizException("ACC45005"));
        WithholdProtocolConfirmOrder withholdProtocolConfirmOrder = new WithholdProtocolConfirmOrder();
        withholdProtocolConfirmOrder.setId(snowflakeIdWorker.nextId());
        withholdProtocolConfirmOrder.setApplyOrderId(withholdProtocolApplyOrder.getId());
        withholdProtocolConfirmOrder.setPrepareId(withholdProtocolApplyOrder.getPrepareId());
        withholdProtocolConfirmOrder.setStatus(Status.INIT.getCode());
        withholdProtocolConfirmOrder.setRequestNo(lanMaoSequence.getRequestNo());
        withholdProtocolConfirmOrder.setVerifyCode(securityCode);

        withholdProtocolConfirmOrder.setCreateTime(new Date());
        withholdProtocolConfirmOrder.setUpdateTime(new Date());
        return withholdProtocolConfirmOrder;
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void createConfirmOrder(WithholdProtocolConfirmOrder withholdProtocolConfirmOrder){
        withholdProtocolConfirmOrderMapper.insert(withholdProtocolConfirmOrder);
    }

    protected WithholdProtocolConfirmOrder submitConfirmOrder(WithholdProtocolConfirmOrder withholdProtocolConfirmOrder){
         return super.confirmProtocolSign(withholdProtocolConfirmOrder);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void saveConfirmOrder(WithholdProtocolConfirmOrder withholdProtocolConfirmOrder){
        if( withholdProtocolConfirmOrder.getStatus().equals(Status.SUCCESS.getCode())){
            WithholdProtocolApplyOrder withholdProtocolApplyOrder = withholdProtocolApplyOrderMapper.selectByPrimaryKey(withholdProtocolConfirmOrder.getApplyOrderId());
            WithholdProtocolSigned withholdProtocolSigned = new WithholdProtocolSigned();
            withholdProtocolSigned.setId(snowflakeIdWorker.nextId());
            withholdProtocolSigned.setPrepareId(withholdProtocolConfirmOrder.getPrepareId());
            AccountBase accountBase = accountService.loadAccountById(withholdProtocolApplyOrder.getAccountId());
            BankCard bankCard = bankCardService.loadBankCard(accountBase);
            withholdProtocolSigned.setUserId(withholdProtocolApplyOrder.getUserId());
            withholdProtocolSigned.setFromSource(FromSource.ONLINE.getCode());
            withholdProtocolSigned.setBankAccountNo(bankCard.getBankAccountNo());
            withholdProtocolSigned.setIdCard(bankCard.getIdCard());
            withholdProtocolSigned.setRealName(bankCard.getRealName());
            withholdProtocolSigned.setMobileNo(bankCard.getMobileNo());
            withholdProtocolSigned.setPayChannelId(withholdProtocolApplyOrder.getPayChannelId());
            withholdProtocolSigned.setCreateTime(new Date());
            withholdProtocolSigned.setUpdateTime(new Date());
            withholdProtocolSigned.setPrepareId(withholdProtocolConfirmOrder.getPrepareId());
            withholdProtocolSignedMapper.insert(withholdProtocolSigned);
        }
        withholdProtocolConfirmOrderMapper.updateByPrimaryKeySelective(withholdProtocolConfirmOrder);
    }


    @Override
    public WithholdProtocolResultDTO getWithholdProtocolResultForLocal(String userId, String orgId) {

        Assert.hasLength(userId,"userId不能为空");
        Assert.hasLength(orgId,"orgId不能为空");
        WithholdProtocolResultDTO withholdProtocolResultDTO = new WithholdProtocolResultDTO();
        AccountBase accountBase = accountService.getAccount(userId, UserRoleEnum.BORROWERS,orgId);
        //Optional.ofNullable(accountBase).orElseThrow(() -> new BizException("ACC10004"));
        if( Objects.isNull( accountBase )){
            log.info("User:{} has not build UserRoleEnum.BORROWERS account ",userId);
            withholdProtocolResultDTO.setResult(Boolean.FALSE);
            return withholdProtocolResultDTO;
        }
        BankCard bankCard = bankCardService.loadBankCard(accountBase);
        WithholdProtocolChannel withholdProtocolChannel = withholdProtocolChannelMapperExt.selectByBankTypeId(bankCard.getBankTypeId());
        //Optional.ofNullable(withholdProtocolChannel).orElseThrow(() -> new BizException("ACC45002"));
        if(Objects.isNull(withholdProtocolChannel)){
            log.info("Withhold protocol channel has not config,User:{},BankCard:{}",JSON.toJSONString(accountBase),JSON.toJSONString(bankCard));
            withholdProtocolResultDTO.setResult(Boolean.FALSE);
            return withholdProtocolResultDTO;
        }
        List<WithholdProtocolSigned> withholdProtocolSignedList = this.checkWithholdProtocolSigned(bankCard.getRealName(),bankCard.getIdCard(),bankCard.getMobileNo(),bankCard.getBankAccountNo(),withholdProtocolChannel.getPayChannelId());
        if ( !withholdProtocolSignedList.isEmpty()){
            for( WithholdProtocolSigned vo : withholdProtocolSignedList ){
                if(vo.getPayChannelId().equals(withholdProtocolChannel.getPayChannelId())){
                    //当前用户已签约   -- 直接返回
                    withholdProtocolResultDTO.setResult(Boolean.TRUE);
                    withholdProtocolResultDTO.setPayChannelId(vo.getPayChannelId());
                    withholdProtocolResultDTO.setExpire(Expire.EFFECTIVE.getCode());
                    return withholdProtocolResultDTO;
                }
            }
            //当前用户有签约后通道失效
            withholdProtocolResultDTO.setResult(Boolean.TRUE);
            withholdProtocolResultDTO.setExpire(Expire.OVERDUE.getCode());
            return withholdProtocolResultDTO;
        }else{
            withholdProtocolResultDTO.setResult(Boolean.FALSE);
            return withholdProtocolResultDTO;
        }

    }

    @Override
    public WithholdProtocolResultDTO getWithholdProtocolResultForRemote(String userId, String orgId) {
        Assert.hasLength(userId,"userId不能为空");
        Assert.hasLength(orgId,"orgId不能为空");
        AccountBase accountBase = accountService.getAccount(userId, UserRoleEnum.BORROWERS,orgId);
        BankCard bankCard = bankCardService.loadBankCard(accountBase);

        WithholdProtocolChannel withholdProtocolChannel = withholdProtocolChannelMapperExt.selectByBankTypeId(bankCard.getBankTypeId());
        Optional.ofNullable(withholdProtocolChannel).orElseThrow(() -> new BizException("ACC45002"));
        PayChannel payChannel = payChannelMapperExt.selectByPrimaryKey(withholdProtocolChannel.getPayChannelId());
        Optional.ofNullable(payChannel).orElseThrow(() -> new BizException("ACC45004"));
        ProtocolSignQueryRequest request = new ProtocolSignQueryRequest();
        request.setPlatformUserNo(accountBase.getAccountNo());
        request.setExpectPayCompany(payChannel.getChannelCode());
        WithholdProtocolResultDTO dto = new WithholdProtocolResultDTO();
        ProtocolSignQueryResponse response = super.queryProtocolSign(request);
        if(response.isSuccess()){
             if("SUCCESS".equals(response.getProtocolStatus())){
                 dto.setResult(Boolean.TRUE);
                 dto.setPayChannelId(payChannel.getId());
             }else{
                 dto.setResult(Boolean.FALSE);
                 dto.setChannelErrorCode(response.getChannelErrorCode());
                 dto.setChannelErrorMessage(response.getChannelErrorMessage());
                 dto.setErrorCode(response.getErrorCode());
                 dto.setErrorMessage(response.getErrorMessage());
             }
        }else{
            dto.setResult(Boolean.FALSE);
            dto.setChannelErrorCode(response.getChannelErrorCode());
            dto.setChannelErrorMessage(response.getChannelErrorMessage());
            dto.setErrorCode(response.getErrorCode());
            dto.setErrorMessage(response.getErrorMessage());
        }
        return dto;
    }

    /**
     * 判断是否已签约
     */
    private List<WithholdProtocolSigned> checkWithholdProtocolSigned(String realName,String IdCard,String mobilNo,String bankAccountNO,long payChannelId){
        WithholdProtocolSignedExample example = new WithholdProtocolSignedExample();
        WithholdProtocolSignedExample.Criteria criteria = example.createCriteria();
        criteria.andRealNameEqualTo(realName);
        criteria.andIdCardEqualTo(IdCard);
        criteria.andMobileNoEqualTo(mobilNo);
        criteria.andBankAccountNoEqualTo(bankAccountNO);
        //criteria.andPayChannelIdEqualTo(payChannelId);
        example.setOrderByClause("create_time desc");
        List<WithholdProtocolSigned> withholdProtocolSignedList = withholdProtocolSignedMapperExt.selectByExample(example);
        return withholdProtocolSignedList;
    }

    public List<WithholdProtocolConfirmOrder> getInitConfirmOrderList(){
        WithholdProtocolConfirmOrderExample example = new WithholdProtocolConfirmOrderExample();
        WithholdProtocolConfirmOrderExample.Criteria criteria = example.createCriteria();
        Date now = new Date();
        Date before = new Date(now.getTime() - scanTime * 60 * 1000);
        criteria.andStatusEqualTo(Status.INIT.getCode());
        criteria.andCreateTimeBetween(before,now);
        criteria.andErrorCodeIsNotNull();
        example.setOrderByClause("create_time asc");
        List<WithholdProtocolConfirmOrder> withholdProtocolConfirmOrderList = withholdProtocolConfirmOrderMapper.selectByExample(example);
        return withholdProtocolConfirmOrderList;
    }

    public void autoCompensation(){
        List<WithholdProtocolConfirmOrder> withholdProtocolConfirmOrderList = getInitConfirmOrderList();
        log.info("auto compensation of withhold-protocol task,start time:{},data size:{},thread-id:{}",new Date(),withholdProtocolConfirmOrderList.size(),Thread.currentThread().getId());
        for(WithholdProtocolConfirmOrder vo : withholdProtocolConfirmOrderList ){
            try{
                WithholdProtocolApplyOrder applyOrder = withholdProtocolApplyOrderMapper.selectByPrimaryKey(vo.getApplyOrderId());
                AccountBase accountBase = accountService.loadAccountById(applyOrder.getAccountId());
                BankCard bankCard = bankCardService.loadBankCard(accountBase);
                WithholdProtocolChannel withholdProtocolChannel = withholdProtocolChannelMapperExt.selectByBankTypeId(bankCard.getBankTypeId());
                PayChannel payChannel = payChannelMapperExt.selectByPrimaryKey(withholdProtocolChannel.getPayChannelId());
                List<WithholdProtocolSigned> withholdProtocolSignedList = this.checkWithholdProtocolSigned(bankCard.getRealName(),bankCard.getIdCard(),bankCard.getMobileNo(),bankCard.getBankAccountNo(),withholdProtocolChannel.getPayChannelId());

                Boolean isCurrentRowSigned = Boolean.FALSE ;
                if( null != withholdProtocolSignedList && withholdProtocolSignedList.size() > 0 ){
                    for( WithholdProtocolSigned signed : withholdProtocolSignedList ){
                        if(signed.getPayChannelId().equals(withholdProtocolChannel.getPayChannelId())){
                            //当前用户已签约   -- 该行数据不需再处理
                            isCurrentRowSigned = Boolean.TRUE;
                        }
                    }
                    if(isCurrentRowSigned){
                        log.info("order id:{} has sign contract on platform ! continue next the data.",vo.getId());
                        continue;
                    }

                }
                ProtocolSignQueryRequest request = new ProtocolSignQueryRequest();
                request.setPlatformUserNo(accountBase.getAccountNo());
                request.setExpectPayCompany(payChannel.getChannelCode());
                WithholdProtocolResultDTO dto = new WithholdProtocolResultDTO();
                ProtocolSignQueryResponse response = super.queryProtocolSign(request);

                if(response.isSuccess()
                        && Status.SUCCESS.getCode().equals(response.getProtocolStatus())
                        && StringUtils.hasText(response.getProtocol())){
                    log.info("platform have not record,E-bank has sign contract,compensation order id:{}",vo.getId());
                    vo.setStatus(Status.SUCCESS.getCode());
                    vo.setUpdateTime(new Date());
                    vo.setErrorMessage(vo.getErrorMessage()+"-存管已签约，平台无数据，补单修复");
                    saveConfirmOrder(vo);
                    continue;
                }
                super.confirmProtocolSign(vo);
                if( vo.getStatus().equals(Status.SUCCESS.getCode())){
                    log.info("platform have not record,E-bank have not sign contract,compensation order id:{}",vo.getId());
                    vo.setUpdateTime(new Date());
                    vo.setErrorMessage(vo.getErrorMessage()+"-平台补单修复");
                    saveConfirmOrder(vo);
                }
            }catch(Exception e){
                log.error("Withhold protocol auto compensation row record RunTimeException:{}", JSON.toJSONString(vo),e);
            }
        }
        log.info("auto compensation of withhold-protocol task,end time:{},data size:{},thread-id:{}",new Date(),withholdProtocolConfirmOrderList.size(),Thread.currentThread().getId());
    }

    public void checkUserWithholdProtocolSigned(){
        long startTime=System.nanoTime();   //获取开始时间
        int countSigneds = withholdProtocolSignedMapperExt.countByExample(new WithholdProtocolSignedExample());
        AtomicInteger index = new AtomicInteger(0);
        int pageSize = 200;
        int cpuMax = Runtime.getRuntime().availableProcessors()*2;
        ExecutorService executor = Executors.newFixedThreadPool(cpuMax);
        List<Callable<Boolean>> callables = new ArrayList<>();
        Callable callable = new Callable() {
            @Override
            public Object call() throws Exception {
                HintManager hintManager = HintManager.getInstance();
                hintManager.setMasterRouteOnly();
                ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
                synchronized (this){
                    threadLocal.set(index.intValue());
                }
                log.info("ThreadId==:"+Thread.currentThread().getId()+"index:"+index.intValue());
                while ( threadLocal.get() * pageSize <= countSigneds) {
                    synchronized (this){
                        index.incrementAndGet();
                    }
                    log.info("threadLocal==:"+threadLocal.get() +"index="+index+"threadId="+Thread.currentThread().getId());
                    WithholdProtocolSignedExample example = new WithholdProtocolSignedExample();
                    PageHelper.startPage(threadLocal.get(), pageSize, false);
                    example.setOrderByClause(" id asc ");
                    List<WithholdProtocolSigned> signeds = withholdProtocolSignedMapperExt.selectByExample(example);
                    for (WithholdProtocolSigned signed : signeds) {
                        try{
                            AccountBase accountBase = accountService.getNiiwooAccount(signed.getUserId(), UserRoleEnum.BORROWERS);
                            PayChannel payChannel = payChannelMapperExt.selectByPrimaryKey(signed.getPayChannelId());
                            ProtocolSignQueryRequest request = new ProtocolSignQueryRequest();
                            request.setPlatformUserNo(accountBase.getAccountNo());
                            request.setExpectPayCompany(payChannel.getChannelCode());
                            ProtocolSignQueryResponse response = queryProtocolSign(request);
                            if (response.isSuccess() ) {
                                if(Status.SUCCESS.name().equals(response.getProtocolStatus())){
                                    continue;
                                }else{
                                    WithholdProtocolSigned signedUpdate = new WithholdProtocolSigned();
                                    signedUpdate.setId(signed.getId());
                                    signedUpdate.setDescription("签约失败");
                                    withholdProtocolSignedMapperExt.updateByPrimaryKeySelective(signedUpdate);
                                    log.info("签约失败id:{},userId:{}", signed.getId(), signed.getUserId());
                                }
                            } else {
                                WithholdProtocolSigned signedUpdate = new WithholdProtocolSigned();
                                signedUpdate.setId(signed.getId());
                                signedUpdate.setDescription("存管-系统内部异常");
                                withholdProtocolSignedMapperExt.updateByPrimaryKeySelective(signedUpdate);
                                log.info("存管-系统内部异常id:{},userId:{}", signed.getId(), signed.getUserId());
                            }
                            /*{  //调试代码
                                withholdProtocolSignedUpdateMaster(signed);
                            }*/
                        }catch (Exception e){
                            log.error("Thread.id={},异常行记录:{}",Thread.currentThread().getId(),JSON.toJSONString(signed),e);
                            WithholdProtocolSigned signedUpdate = new WithholdProtocolSigned();
                            signedUpdate.setId(signed.getId());
                            signedUpdate.setDescription(e.toString());
                            withholdProtocolSignedMapperExt.updateByPrimaryKeySelective(signedUpdate);
                        }
                    }
                    threadLocal.set(index.intValue());
                }
                return Boolean.TRUE;
            }
        };
        for(int iThread = 0 ; iThread < cpuMax ; iThread ++ ){
            callables.add(callable);
        }
        try {
            executor.invokeAll(callables)
                    .stream()
                    .map(future -> {
                        try {
                            boolean lsResult = (Boolean)future.get();
                            if( ! lsResult ){
                                throw new BizException("系统异常");
                            }
                            return future.get();
                        }
                        catch (Exception e) {
                            throw new IllegalStateException(e);
                        }
                    });
            executor.shutdown();
        } catch (InterruptedException e) {
            log.error("协议签约异常：",e);
        }
        long endTime=System.nanoTime(); //获取结束时间
        log.info("程序运行时间： "+(endTime-startTime)+"ns");
    }

    /**
     * 检测多线程方法，实际没有调用
     * @param signed
     */
    public void withholdProtocolSignedUpdateMaster(WithholdProtocolSigned signed){
        WithholdProtocolSigned signedUpdate = new WithholdProtocolSigned();
        signedUpdate.setId(signed.getId());
        signedUpdate.setDescription("check");
        withholdProtocolSignedMapperExt.updateByPrimaryKeySelective(signedUpdate);
    }
}
